package com.runa.monitor.platinterface.netservice.equipment;

import com.runa.monitor.comm.dto.Archive;
import com.runa.monitor.comm.dto.Node;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.persistence.SerializeUtil;
import com.runa.rccprotocol.dto.AffirmDeny;
import com.runa.rccprotocol.dto.equdata.EquData;
import com.runa.rccprotocol.dto.param.ExtendParam;
import lombok.Builder;
import lombok.Data;
import okhttp3.*;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class BlackAntWebDriver extends NetEqu<String> {

    private String host;

    private String username;

    private String password;

    private String dbUrl;

    private String dbUser;

    private String dbPassword;

    private OkHttpClient httpClient;

    public BlackAntWebDriver(String serial, Integer timeout,
                             String host, String username, String password,
                             String dbUrl, String dbUser, String dbPassword) {
        super(serial, timeout);
        this.host = host;
        this.username = username;
        this.password = password;
        this.dbUrl = dbUrl;
        this.dbUser = dbUser;
        this.dbPassword = dbPassword;
        this.httpClient = new OkHttpClient()
                .newBuilder()
                .callTimeout(timeout, TimeUnit.MILLISECONDS)
                .build();
    }

    private final AtomicInteger id = new AtomicInteger(1);

    private synchronized Integer getId() {
        int andIncrement = id.getAndIncrement();
        if(andIncrement == 65535){
            id.set(1);
            andIncrement = 1;
        }
        return andIncrement;
    }

    @Override
    public void readNodeEqu(List<Node> nodes, TaskFunction function, EquData.EquDataType type) {
        if (type == EquData.EquDataType.PUBLIC_UNIT
                || type == EquData.EquDataType.VALVE) {
            try {
                function.doApply(CommStatus.OK, queryData(nodes.stream().map(Node::getSerial).collect(Collectors.toList())));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    private List<ValveVO> queryData(List<String> ids) throws Exception {
        String sql = " SELECT * FROM `view_valve_status_real_taiyuandiregongre` WHERE NODEID IN("+String.join(",", ids)+")";
        ResultSet rs = this.query(sql, null);
        List<ValveVO> result = new ArrayList<>();
        while (rs.next()) {
            ValveVO valveVO = new ValveVO();
            String nodeId = rs.getString("NODEID");
            valveVO.setValveSerial(nodeId);
            Float supplyTem = rs.getFloat("TEMP_INTAKE");
            valveVO.setSupplyTemp(supplyTem);
            Float returnTem = rs.getFloat("TEMP_RETURN");
            valveVO.setReturnTemp(returnTem);
            int valve_opening = rs.getInt("VALVE_OPENING");
            valveVO.setActOpen((float) valve_opening);
            int set_opening = rs.getInt("SET_OPENING");
            valveVO.setRemoteSet((float) set_opening);
            Date deviceTime = rs.getDate("TIME_DEVICE");
            valveVO.setValveDate(deviceTime);
            Float houseTem = rs.getFloat("TEMP_INDOOR");
            valveVO.setEnvTemp(houseTem);
//            Float temp_set = rs.getFloat("TEMP_SET");
//            valveVO.set(temp_set);
            result.add(valveVO);
        }
        this.close();
        return result;
    }

    public ResultSet query(String sql, Object[] object) throws Exception{
        Connection con = this.loading(); //调用加载方法 进行加载驱动和建立连接
        PreparedStatement pstmt = con.prepareStatement(sql); //创建一个预编译通道 对象
        ResultSet rs;
        //返回 查询信息的集合
        //最后执行executeQuery()方法 执行sql语句
        for(int i=0;i<object.length;i++){
            pstmt.setObject(i+1,object[i]);
        }
        rs = pstmt.executeQuery();
        return rs;
    }

    private Connection connection;

    public Connection loading() throws Exception{
//        String driver = "com.mysql.jdbc.Driver";
//        String url = "jdbc:mysql://121.42.239.167:3306/iot2020?serverTimezone=UTC&useUnicode=true&characterEncoding=GBK&zeroDateTimeBehavior=convertToNull";
//        String username = "jashy";
//        String password = "jashy@2019.";
//		Class.forName("com.mysql.cj.jdbc.Driver");
//		con = DriverManager.getConnection("jdbc:mysql://localhost:3306/girls?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL","root","root");
        Class.forName("com.mysql.jdbc.Driver"); //加载驱动
        if (connection == null || connection.isClosed()) {
            connection = DriverManager.getConnection(dbUrl,dbUser,dbPassword); //创建连接
        }
        return connection;
    }

    @Override
    public void setNodeEquArchive(List<Archive> archives, TaskFunction function) {

    }

    @Override
    public void clearNodeEquArchive(TaskFunction function) {
    }

    @Override
    public void valveOnOffControl(List<Node> nodeList, boolean ifLock, Integer opening, TaskFunction function) {

    }

    @Override
    public void readNodeRecord(List<Integer> indexes, TaskFunction function) {

    }

    @Override
    public void sentPublicUnitRecord(List<Node> nodeList, Integer model, Map param, TaskFunction function) {
        for (Node valve : nodeList) {
            if (model == 1) {
                DateFormat callingFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                DateFormat expireFormat = new SimpleDateFormat("yyyy-MM-dd");
                for (Node node : nodeList) {
                    ValveParam valveParam = new ValveParam();
                    UserInfo userInfo = UserInfo.builder().user(username).password(password).build();
                    Integer id = getId();
                    valveParam.setUserInfo(userInfo);
                    valveParam.setCalling_time(callingFormat.format(new Date()));
                    valveParam.setExpire_date(expireFormat.format(new Date()));
                    valveParam.setMsg_id(id);
                    valveParam.setOpening((int) Float.parseFloat(param.get("targetValue").toString()));
                    try {
                        Response response = httpClient.newCall(new Request.Builder().url(this.host + "/v501/set_opening")
                                .post(RequestBody.create(Objects.requireNonNull(SerializeUtil.obj2json(param)),
                                        MediaType.parse("application/json; charset=utf-8")))
                                .build()).execute();
                        function.setStatus(node);
                        if (response.isSuccessful()) {
                            function.doApply(CommStatus.OK, new AffirmDeny() {
                                @Override
                                public Boolean getData() {
                                    return true;
                                }
                            });
                        } else {
                            function.doApply(CommStatus.OK, new AffirmDeny() {
                                @Override
                                public Boolean getData() {
                                    return false;
                                }
                            });
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    @Override
    public void sentPublicUnitModel(List<Node> nodeList, boolean model, TaskFunction function) {

    }

    @Override
    public void sentExtendParam(ExtendParam param, TaskFunction function) {

    }

    @Override
    public void readPublicUnitRecord(Node valve, Integer model, TaskFunction function) {

    }

    @Override
    public void readPublicUnitAndMeter(Node valve, Node meter, TaskFunction function) {

    }

    @Override
    public void heartbeatUpdate() {

    }

    @Override
    public boolean heartStop() {
        return false;
    }


    @Data
    @Builder
    static
    class UserInfo {
        private String user;
        private String password;
    }

    static
    class Param {
        private UserInfo userInfo;
        private Integer msg_id;
        private String device_id;
        private String calling_time;
        private String expire_date;

        public UserInfo getUserInfo() {
            return userInfo;
        }

        public void setUserInfo(UserInfo userInfo) {
            this.userInfo = userInfo;
        }

        public Integer getMsg_id() {
            return msg_id;
        }

        public void setMsg_id(Integer msg_id) {
            this.msg_id = msg_id;
        }

        public String getDevice_id() {
            return device_id;
        }

        public void setDevice_id(String device_id) {
            this.device_id = device_id;
        }

        public String getCalling_time() {
            return calling_time;
        }

        public void setCalling_time(String calling_time) {
            this.calling_time = calling_time;
        }

        public String getExpire_date() {
            return expire_date;
        }

        public void setExpire_date(String expire_date) {
            this.expire_date = expire_date;
        }
    }

    static
    class ValveParam extends Param {
        private Integer opening;

        public Integer getOpening() {
            return opening;
        }

        public void setOpening(Integer opening) {
            this.opening = opening;
        }
    }

}
